/*
 * INCLUDE FILES
 ****************************************************************************************
 */
#include <stdio.h>
#include <string.h>

#include "gap_api.h"
#include "gatt_api.h"
#include "ble_stack.h"
#include "app_config.h"

#include "jump_table.h"
#include "co_log.h"

#include "plf.h"
#include "driver_system.h"
#include "driver_pmu.h"
#include "driver_uart.h"

#include "ble_simple_central.h"
#include "simple_gatt_service.h"

#undef LOG_LOCAL_LEVEL
#define LOG_LOCAL_LEVEL        (LOG_LEVEL_INFO)
const char *app_tag = "project";

#define SYSTEM_STACK_SIZE           0x800

/*
 * LOCAL VARIABLES
 */

__attribute__((section("stack_section"))) static uint32_t system_stack[SYSTEM_STACK_SIZE/sizeof(uint32_t)];

const struct jump_table_version_t _jump_table_version __attribute__((section("jump_table_3"))) = 
{
    .stack_top_address = &system_stack[SYSTEM_STACK_SIZE/sizeof(uint32_t)],
    .firmware_version = 0x00000000,
};

const struct jump_table_image_t _jump_table_image __attribute__((section("jump_table_1"))) =
{
    .image_type = IMAGE_TYPE_APP,
    .image_size = 0x19000,      
};

/*********************************************************************
 * @fn      user_entry_before_sleep_imp
 *
 * @brief   Before system goes to sleep mode, user_entry_before_sleep_imp()
 *          will be called, MCU peripherals can be configured properly before 
 *          system goes to sleep, for example, some MCU peripherals need to be
 *          used during the system is in sleep mode. 
 *
 * @param   None. 
 *       
 *
 * @return  None.
 */
__attribute__((section("ram_code"))) void user_entry_before_sleep_imp(void)
{
	uart_putc_noint_no_wait(UART0, 's');
}

/*********************************************************************
 * @fn      user_entry_after_sleep_imp
 *
 * @brief   After system wakes up from sleep mode, user_entry_after_sleep_imp()
 *          will be called, MCU peripherals need to be initialized again, 
 *          this can be done in user_entry_after_sleep_imp(). MCU peripherals
 *          status will not be kept during the sleep. 
 *
 * @param   None. 
 *       
 *
 * @return  None.
 */
__attribute__((section("ram_code"))) void user_entry_after_sleep_imp(void)
{
	system_set_port_mux(GPIO_PORT_A, GPIO_BIT_0, PORTA0_FUNC_UART0_RXD);
    system_set_port_mux(GPIO_PORT_A, GPIO_BIT_1, PORTA1_FUNC_UART0_TXD);
    uart_init(UART0, 1152);
    fr_uart_enableIrq(UART0, Uart_irq_erbfi);
	
	uart_putc_noint_no_wait(UART0, 'w');
	NVIC_EnableIRQ(PMU_IRQn);	
}

__attribute__((section("ram_code"))) void main_loop(void)
{
    while(1)
    {
        if(ble_stack_schedule_allow())
        {
            /*user code should be add here*/
            
            /* schedule internal stack event */
            ble_stack_schedule();
        }
        
        GLOBAL_INT_DISABLE();
        switch(ble_stack_sleep_check())
        {
            case 2:
            {
                ble_stack_enter_sleep();
                __jump_table.diag_port = 0x00008300;
                *(volatile uint32_t *)0x50000024 = 0xeeeeeeee;
            }
            break;
            default:
                break;
        }
        GLOBAL_INT_RESTORE();
        
        ble_stack_schedule_backward();
    }
}

/*********************************************************************
 * @fn      proj_init
 *
 * @brief   Main entrancy of user application. This function is called after BLE stack
 *          is initialized, and all the application code will be executed from here.
 *          In that case, application layer initializtion can be startd here. 
 *
 * @param   None. 
 *       
 *
 * @return  None.
 */
void proj_init(void)
{
    LOG_INFO(app_tag, "BLE Central\r\n");
    
    // Application layer initialization, can included bond manager init, 
    // advertising parameters init, scanning parameter init, GATT service adding, etc.    
    simple_central_init();
}

/*********************************************************************
 * @fn      user_entry_before_ble_init
 *
 * @brief   Code to be executed before BLE stack to be initialized.
 *          Power mode configurations, PMU part driver interrupt enable, MCU 
 *          peripherals init, etc. 
 *
 * @param   None. 
 *       
 *
 * @return  None.
 */
void user_main(void)
{    
    /* initialize log module */
    log_init();

    /* initialize PMU module at the beginning of this program */
    pmu_sub_init();

    /* set system clock */
    system_set_clock(SYSTEM_CLOCK_SEL);

    /* set local BLE address */
    mac_addr_t mac_addr;
    mac_addr.addr[0] = 0xbd;
    mac_addr.addr[1] = 0xad;
    mac_addr.addr[2] = 0x10;
    mac_addr.addr[3] = 0x11;
    mac_addr.addr[4] = 0x20;
    mac_addr.addr[5] = 0x20;
    gap_address_set(&mac_addr, BLE_ADDR_TYPE_PRIVATE);
    /* configure ble stack capabilities */
    ble_stack_configure(BLE_STACK_ENABLE_MESH,
                        BLE_STACK_ENABLE_CONNECTIONS,
                        BLE_STACK_RX_BUFFER_CNT,
                        BLE_STACK_RX_BUFFER_SIZE, 
                        BLE_STACK_TX_BUFFER_CNT, 
                        BLE_STACK_TX_BUFFER_SIZE, 
                        BLE_STACK_ADV_BUFFER_SIZE,
                        BLE_STACK_RETENTION_RAM_SIZE,
                        BLE_STACK_KEY_STORAGE_OFFSET);
    /* initialize ble stack */
    ble_stack_init();
    /* initialize SMP */
    gap_bond_manager_init(BLE_BONDING_INFO_SAVE_ADDR, BLE_REMOTE_SERVICE_SAVE_ADDR, 8, true);

    proj_init();

    /* enter main loop */
    main_loop();
}
